package p4_student;



/**
 * A general representation of a 2nd degree Martian polynomial of the form:
 * (a*x^2 + b*x + c)
 * 
 * @author: Alishba Khawaja
 * @TA: Jason fillipou
 * @section: 0204
 * @date : 28 October 2012
 */

public class MartianPolynomial {
	private final MyDouble a;
	private final MyDouble b;
	private final MyDouble c;

	public MartianPolynomial() {
		a = MyDouble.zero;
		b = MyDouble.zero; 
		c = MyDouble.zero;
	}

	/**
	 * Constructor that has 3 parameters passed in
	 * @param val1, a MyDouble
	 * @param val2, a MyDouble
	 * @param val3, a MyDouble
	 */
	public MartianPolynomial(MyDouble val1, MyDouble val2, MyDouble val3){
		a = val1;
		b = val2;
		c = val3;

	}

	/**
	 * Constructor that has 2 parameters passed in
	 * @param val2, a MyDouble
	 * @param val3, a MyDouble
	 */

	public MartianPolynomial(MyDouble val2, MyDouble val3 ){
		this( MyDouble.zero, val2, val3);

	}

	/**
	 * Constructor that has 1 parameter passed in
	 * @param val3, a MyDouble
	 */

	public MartianPolynomial(MyDouble val3){
		this( MyDouble.zero, MyDouble.zero, val3);

	}
	/**
	 * A copy constructor
	 * @param val, a MartianPolynomial
	 */

	public MartianPolynomial(MartianPolynomial val){
		this(val.getA(),val.getB(), val.getC());

	}

	/**
	 * Method to get value of coefficient a
	 * @return value of a
	 */

	public MyDouble getA(){

		return a;
	}

	/**
	 * Method to get value of coefficient b
	 * @return value of b
	 */

	public MyDouble getB(){

		return b;
	}
	/**
	 * Method to get the value of coefficient c
	 * @return value of c
	 */


	public MyDouble getC(){

		return c;
	}

	/**
	 * Method to evaluate the polynomial with a value passed
	 * @param value, a MyDouble
	 * @return evaluation, a MyDouble
	 */


	public MyDouble eval(MyDouble value){
		MyDouble evaluation = (a.multiply(value).multiply(value)).add
				(b.multiply(value)).add(c);

		return evaluation;
	}

	/**
	 * Method returns a new MartianPolynomial that is equal to the sum of the 
	 * current object and the parameter
	 * @param number, a MartianPolynomial
	 * @return sum, a MartianPolynomial
	 */



	public MartianPolynomial add(MartianPolynomial number){
		MyDouble sumA = a.add(number.getA());
		MyDouble sumB = b.add(number.getB());
		MyDouble sumC = c.add(number.getC());

		MartianPolynomial sum = new MartianPolynomial(sumA, sumB, sumC);

		return sum;
	}

	/**
	 * Method return a MartianPolynomial that is computed by subtracting the 
	 * value of the parameter from the current object
	 * @param number, a MartianPolynomial
	 * @return subtract, a MartianPolynomial
	 */
	public MartianPolynomial subtract(MartianPolynomial number){
		MyDouble subtractA = a.subtract(number.getA());
		MyDouble subtractB = b.subtract(number.getB());
		MyDouble subtractC = c.subtract(number.getC());

		MartianPolynomial subtract = new MartianPolynomial(subtractA, subtractB, 
				subtractC);

		return subtract;
	}

	/**
	 * Method returns a MartianPolynomial which is the glorp of the current 
	 * object and the parameter. However, if the resulting MartianPolynomial 
	 * would end up having a third or fourth order term, then the method must 
	 * return null.
	 * @param number, a MartianPolynomial
	 * @return null(in case of third or fourth order) or glorp, a Martian
	 * Polynomial
	 */

	public MartianPolynomial glorp(MartianPolynomial number){
		MyDouble glorp4 = a.multiply(number.getC());//a*f
		MyDouble glorp3 = (a.multiply(number.getB()).add
				(b.multiply(number.getC())));
		if(!(glorp4.equals(MyDouble.zero))|| !(glorp3.equals(MyDouble.zero) )){
			return null;
		}


		MyDouble glorp2 = (c.multiply(number.getC()).add(b.multiply
				(number.getB()).add(a.multiply(number.getA()))));

		MyDouble glorp1 = (c.multiply(number.getB())).add(b.multiply
				(number.getA()));

		MyDouble glorp0 = c.multiply(number.getA());

		MartianPolynomial glorp = new MartianPolynomial(glorp2, glorp1, glorp0);

		return glorp;

	}

	/**
	 * Method returns a new MartianPolynomial that is computed by taking the 
	 * splee of the current object.The way to take the splee of a Maritan- 
	 * Polynomial "ax^2 + bx + c" is "4acx + bc"
	 * @return splee, a MartianPolynomial
	 */

	public MartianPolynomial splee(){


		MyDouble coefficient = new MyDouble(4);	
		MyDouble splee1 = coefficient.multiply(a.multiply(c));//4*a*c
		MyDouble splee0 = b.multiply(c);//b*c
		MartianPolynomial splee = new MartianPolynomial(splee1, splee0);

		return splee;

	}

	/**
	 * Method returns a new MyDouble object representing the cliff of the 
	 * current object. The definition of taking the cliff of a MartianPolynomial 
	 * is: {square root((a+b+c)^2)}.
	 * @return squareRoot, MyDouble
	 */

	public MyDouble cliff(){

		MyDouble sum = (a.add(b)).add(c);//a+b+c
		MyDouble square = sum.square();//sum^2
		MyDouble squareRoot = square.sqrt();//squareRoot^1/2

		return squareRoot;
	}

	/**
	 * Method compares the cliffof the current object with the cliff of the
	 * parameter. If the cliffs are equal, this method returns 0; if the cliff
	 * of the current object is less than the cliff of the parameter, this
	 * method returns -1; if the cliff of the current object is greater than 
	 * the cliff of the parameter, this method returns +1.
	 * @param number, a MartianPolynomial
	 * @return "0" or "-1" or "1"
	 */

	public int compareTo(MartianPolynomial number){

		if(this.cliff().equals(number.cliff())){
			return 0;
		}

		else if(this.cliff().compareTo(number.cliff())<0){
			return -1;

		}

		else if(this.cliff().compareTo(number.cliff()) > 0){
			return 1;
		}
		else{
			return 0;
		}

	}


	/**
	 * Method returns a new String representing the polynomial. The returned 
	 * string has no spaces, no "*", no coefficients of x^2 or x as "0" and no
	 * decimal component for coefficient 0
	 * @return result, the new String or 0
	 */
	public String toString(){

		String result ="";//empty string
		if(!a.equals(MyDouble.zero)){
			result+= a+"x^2";
		}

		if(!b.equals(MyDouble.zero))
		{
			if(b.compareTo(MyDouble.zero) > 0 && result.length()>0 ){
				result+= "+"+b+"x";
			}
			else
			{
				
					result+= b+"x";
				
			}
		}
		
		if(!c.equals(MyDouble.zero))
		{
			if(c.compareTo(MyDouble.zero) > 0 && result.length()>0 ){
				result+= "+"+c;
			}
			else
			{
				
					result+= c;
				
			}
		}

		if(result.length()>0)
			return result;
		else
			return "0";
	}

	/**
	 * Method removes all spaces in the string passed, splits this string at 
	 * the arithmetic operators, and passes the returned value to the method
	 * IdentifyCoeff
	 * @param polynomial, a string
	 * @return martianPoly, a new insatance of MartianPolynomial
	 */


	public static MartianPolynomial parseMartianPolynomial(String polynomial){
		MartianPolynomial martianPoly;
		if(polynomial.isEmpty()){
			MyDouble a = MyDouble.zero;
			MyDouble b = MyDouble.zero;
			MyDouble c = MyDouble.zero;
			martianPoly = new MartianPolynomial(a,b,c);
		}else{
			String strP= polynomial.replaceAll(" ", "");//gets rid of empty spaces
			String arithOperator = "[+-]";
			String[] coEfficients;
			coEfficients = strP.split(arithOperator);//splits when +,- found
			martianPoly = IdentifyCoeff(coEfficients, strP);
		}
		return martianPoly;
	}

	/**
	 * Method is iterating over the string array and identifying coefficient a,
	 * b and c and their arithmetic signs. Uses the created values a, b 
	 * and c and sets them to new MartialPolynomial object
	 * @param coeff, a String array
	 * @param strPoly, a string
	 * @return mp, a MartianPolynomial
	 */

	public static MartianPolynomial IdentifyCoeff(String[] coeff, 
			String strPoly){
		String  strA="", strB="",strC="";
		int index=0;

		for(int i =0; i < coeff.length ; i++){//iterating over all the strings
			if(coeff[i].contains("^")){//finding coefficient a
				index = strPoly.indexOf("^")-1;
				strA = strPoly.substring(0, index);
				strPoly = strPoly.substring(index+3, strPoly.length());
			}
			else if(coeff[i].contains("x")){//finding coefficient b
				index = strPoly.indexOf("x");
				strB = strPoly.substring(0, index);
				strPoly = strPoly.substring(index+1, strPoly.length());
			}
			else if(coeff[i].length()<=0)
			{}//ignoring empty value
			else{
				strC = strPoly.substring(0, strPoly.length());//assigning 
				//coefficient c 
				//value
			}
		}
		//creating MyDouble objects for all coefficients
		MyDouble coefA,coefB,coefC;
		//checking for empty coefficients
		if(strA.isEmpty()){
			coefA = new MyDouble(MyDouble.zero);
		}else{
			coefA = new MyDouble(Double.parseDouble(strA));
		}
		if(strB.isEmpty()){
			coefB = new MyDouble(MyDouble.zero);
		}else{
			coefB = new MyDouble(Double.parseDouble(strB));
		}
		if(strC.isEmpty()){
			coefC = new MyDouble(MyDouble.zero);
		}else{
			coefC = new MyDouble(Double.parseDouble(strC));
		}

		MartianPolynomial mp = new MartianPolynomial(coefA,coefB,coefC);
		return mp;

	}
	//NOTE: THIS IS WRITTEN FOR YOU - DO NOT CHANGE
	public boolean equals (Object other) {
		if (other == null) {
			return false;
		}
		else if (this.getClass()!=other.getClass()) {
			return false;
		}
		else {
			MartianPolynomial casted = (MartianPolynomial)other;
			return (
					a.equals(casted.a) && 
					b.equals(casted.b) && 
					c.equals(casted.c)
					);
		}
	}


}